#!/bin/sh
#
# Copyright (c) 2015 Martin Lucina.  All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#

#
# cc.in/c++.in: rumprun backend C/C++ compiler wrapper script
#

die()
{
	exit 1
}

PROGNAME=${0##*/}

# Determine if we're being run as C or C++.
case ${PROGNAME} in
*-gcc|*-clang)
	CC="!LIBEXEC_CC!"
	CFLAGS="!CFLAGS!"
	EXTRALIBS=
	;;
*-g++|*-clang++)
	CC="!LIBEXEC_CXX!"
	CFLAGS="!CXXFLAGS!"
	EXTRALIBS="-lc++ -lunwind"
	;;
*)
	echo "${PROGNAME}: internal error, unknown invocation"
	exit 1
	;;
esac

PRMETA="$(dirname ${CC})/brprintmetainfo"

# Figure out what we're supposed to be doing. Assume we're fermenting
# and switch to compilation if -c / -S / -E was passed.
MODE=ferment
WANTARG=
# OUTFILE gets set to whatever is specified with -o (the real output file).
OUTFILE=a.out
for arg in "$@"; do
	[ "${arg}" = "-c" ] && MODE=compile
	[ "${arg}" = "-S" ] && MODE=compile
	[ "${arg}" = "-E" ] && MODE=compile
	[ "${arg}" = "-o" ] && WANTARG=yes && continue
	[ -n "${WANTARG}" ] && OUTFILE=${arg} && WANTARG=

	# If either of these is present on the command line, the
	# behaviour of gcc seems to be that they silently override
	# all other flags
	[ "${arg}" = "-dumpmachine" ] && { MODE=dumpmachine; break; }
	[ "${arg}" = "-dumpspecs" ] && { MODE=dumpspecs; break; }

	# even if the backing compiler supports multiarch, we do not
	[ "${arg}" = "-print-multiarch" ] && \
	    { echo "${PROGNAME}: unrecognized option '-print-multiarch'" 2>&1;
	      exit 1; }
done

case ${MODE} in
compile)
	exec ${CC} ${CFLAGS} -no-integrated-cpp \
	    --sysroot !DESTDIR!/rumprun-!MACHINE_GNU_ARCH! \
	    -specs=!DESTDIR!/rumprun-!MACHINE_GNU_ARCH!/lib/specs-compile_or_ferment \
	    "$@" ${EXTRALIBS}
	;;
ferment)
	meta1="$(${PRMETA} "${OUTFILE}" 2>/dev/null)"

	# Link the real (from user's PoV) output file as a relocatable object,
	# with no rump components. '-u main' is necessary to pull in main if the
	# user is linking it in from a library.
	${CC} ${CFLAGS} -no-integrated-cpp \
	    --sysroot !DESTDIR!/rumprun-!MACHINE_GNU_ARCH! \
	    -specs=!DESTDIR!/rumprun-!MACHINE_GNU_ARCH!/lib/specs-compile_or_ferment \
	    !EXTRACCFLAGS! -Wl,-r -Wl,-u,main \
	    "$@" !DESTDIR!/rumprun-!MACHINE_GNU_ARCH!/share/!TOOLTUPLE!-recipe.s ${EXTRALIBS} || die

	# If the presumed output file did not change, and the compiler
	# did not flag an error, assume this is a command which does not
	# generate output (e.g. cc -dumpspecs) and exit gracefully
	meta2="$(${PRMETA} "${OUTFILE}" 2>/dev/null)"
	[ "${meta1}" != "${meta2}" ] || exit 0

	if [ "${RUMPRUN_STUBLINK}" = succeed ]; then
		exec 3>&1 2>&1
		echo '!!!'
		echo '!!! WARNING: $RUMPRUN_STUBLINK may be desupported without'
		echo '!!!          warning in the future.  Do not rely on it'
		echo '!!!          continuing to be available.'
		echo '!!!'
		exec 1>&3 3>&-
	fi

	# Try a stub link with minimal rump components. If that fails then stop.
	${CC} ${CFLAGS} -no-integrated-cpp \
	    --sysroot !DESTDIR!/rumprun-!MACHINE_GNU_ARCH! \
	    -specs=!DESTDIR!/rumprun-!MACHINE_GNU_ARCH!/lib/specs-stub \
	    ${OUTFILE} -o /dev/null
	if [ $? -ne 0 ]; then
		if [ "${RUMPRUN_STUBLINK}" = "succeed" ]; then
			echo "${PROGNAME}: warning: stub link failed" 1>&2
		else
			[ -f "${OUTFILE}" ] && rm -f ${OUTFILE}
			die
		fi
	fi

	# Some build systems insist that the output looks like an executable.
	chmod +x ${OUTFILE}
	;;

dumpmachine)
	echo !TOOLTUPLE!
	;;

dumpspecs)
	${CC} -dumpspecs
	cat !DESTDIR!/rumprun-!MACHINE_GNU_ARCH!/lib/specs-compile_or_ferment
	;;

*)
	echo "${PROGNAME}: internal error, unknown mode"
	exit 1
	;;
esac

exit 0
